<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>第一个three.js文件_WebGL三维场景</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            /*隐藏body区域滚动条*/
        }
    </style>
    <script src="js/three.js"></script>
    <script src="js/OrbitControls.js"></script>
    <script src="js/CanvasRenderer.js"></script>
    <script src="js/stats.min.js"></script>
    <script src="js/tween.min.js"></script>
</head>
<body>
<script>

    var container = document.createElement( 'div' );
    document.body.appendChild( container );
    /**
     * 创建场景对象
     */
    var scene = new THREE.Scene()
    /**
     * 创建网络模型
     */
    //正方体
    // var geometry = new THREE.BoxGeometry(100, 100, 100)
    // 球体
    // var geometry = new THREE.SphereGeometry(50, 40, 40)
    //圆柱体，1：上半径，2：下半径，3：高度，4：圆形的精度1-10就是底部就是几边形
    var geometry = new THREE.CylinderBufferGeometry(50, 40, 100,40)
    //正八面体
    // var geometry = new THREE.OctahedronGeometry(100)
    //正12面体
    // var geometry = new THREE.DodecahedronGeometry(100)
    //二十面体
    // var geometry1 = new THREE.BoxGeometry(100, 100, 100)
    var material1 = new THREE.MeshLambertMaterial({
        color: 0xff0000,
        opacity:0.4,
        transparent:true
    })//材质对象
    var mesh1 = new THREE.Mesh(geometry, material1)
    mesh1.translateX(100)
    // 网络模型添加到场景中
    // scene.add(mesh1)


    var geometry2 = new THREE.BoxGeometry(100, 100, 100)
    var material2 = new THREE.MeshPhongMaterial({
        color: 0x00ff00,
        specular:0x4488ee,
        shininess:20
    })//材质对象
    var mesh2 = new THREE.Mesh(geometry2, material2)
    mesh2.translateX(-100)
    // 网络模型添加到场景中
    // scene.add(mesh2)

    // 辅助坐标系  参数250表示坐标系大小，可以根据场景大小去设置
    var axisHelper = new THREE.AxisHelper(2500)
    scene.add(axisHelper)
    var krq = new THREE.Object3D();
    //
    // var x = 0, y = 0;
    //
    // var heartShape = new THREE.Shape();
    //
    // heartShape.moveTo( x + 10, y + 10 );
    // heartShape.bezierCurveTo(x+100,y+100,x+80,y,x,y)
    // heartShape.bezierCurveTo( x + 10, y + 10, x + 8, y, x, y );
    // heartShape.bezierCurveTo( x - 12, y, x - 12, y + 14,x - 12, y + 14 );
    // heartShape.bezierCurveTo( x - 12, y + 22, x - 6, y + 30.8, x + 10, y + 38 );
    // heartShape.bezierCurveTo( x + 24, y + 38, x + 32, y + 22, x + 32, y + 14 );
    // heartShape.bezierCurveTo( x + 32, y + 14, x + 32, y, x + 20, y );
    // heartShape.bezierCurveTo( x + 14, y, x + 10, y + 10, x + 10, y + 10 );

    // var geometry = new THREE.ShapeBufferGeometry( heartShape );
    // var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
    // var mesh3 = new THREE.Mesh( geometry, material ) ;
    // var curve = new THREE.CatmullRomCurve3( [
    //     new THREE.Vector3( 0, 90, 0 ),
    //     new THREE.Vector3( 50, 120, 0 ),
    //     new THREE.Vector3( 80, 100, 0 ),
    //     new THREE.Vector3( 0, 0, 0 ),
    //     new THREE.Vector3( -80, 100, 0 ),
    //     new THREE.Vector3( -50, 120, 0 ),
    //     new THREE.Vector3( 0, 90, 0 )
    // ] );
    //
    // var points = curve.getPoints( 50 );
    // var geometry = new THREE.LatheBufferGeometry( points );

    // var points = [
    //     new THREE.Vector3(-50, -50,0),
    //     new THREE.Vector3(-60, 0,10),
    //     new THREE.Vector3(0, 50,20),
    //     new THREE.Vector3(60, 0,30),
    //     new THREE.Vector3(50, -50,40),
    //     new THREE.Vector3(-50, -50,50),
    // ]
    // // 通过顶点定义轮廓
    // var shape = new THREE.Vertic(points);
    // // shape可以理解为一个需要填充轮廓
    // // 所谓填充：ShapeGeometry算法利用顶点计算出三角面face3数据填充轮廓
    // var geometry = new THREE.ShapeGeometry(shape, 250);
    // // var geometry = new THREE.ExtrudeGeometry(//拉伸造型
    // //     shape,//二维轮廓
    // //     //拉伸参数
    // //     {
    // //         amount:120,//拉伸长度
    // //         bevelEnabled:false//无倒角
    // //     }
    // // );
    // var material = new THREE.MeshPhongMaterial({
    //     color: 0x00ff00,
    //     specular:0x4488ee,
    //     shininess:20
    // })//材质对象
    // // Create the final object to add to the scene
    // var curveObject = new THREE.Mesh( geometry, material );
    // scene.add( curveObject )

    // // 创建多段线条的顶点数据
    // var p1 = new THREE.Vector3(-85.35, -35.36)
    // var p2 = new THREE.Vector3(-50, 0, 0);
    // var p3 = new THREE.Vector3(0, 50, 0);
    // var p4 = new THREE.Vector3(50, 0, 0);
    // var p5 = new THREE.Vector3(85.35, -35.36);
    // // 创建线条一：直线
    // let line1 = new THREE.LineCurve3(p1,p2);
    // // 重建线条2：三维样条曲线
    // var curve = new THREE.CatmullRomCurve3([p2, p3, p4]);
    // // 创建线条3：直线
    // let line2 = new THREE.LineCurve3(p4,p5);
    // var CurvePath = new THREE.CurvePath();// 创建CurvePath对象
    // CurvePath.curves.push(line1, curve, line2);// 插入多段线条
    // //通过多段曲线路径创建生成管道
    // //通过多段曲线路径创建生成管道，CCurvePath：管道路径
    // var geometry = new THREE.TubeGeometry(CurvePath, 100, 5, 25, false);
    // var material = new THREE.MeshPhongMaterial({
    //     color: 0x00ff00,
    //     specular:0x4488ee,
    //     shininess:20
    // })//材质对象
    // var curveObject = new THREE.Mesh( geometry, material );
    // scene.add( curveObject )

    // var geometry = new THREE.BufferGeometry(); //创建一个Buffer类型几何体对象
    // //类型数组创建顶点数据
    // var vertices = new Float32Array([
    //     0, 0, 0, //顶点1坐标
    //     50, 0, 0, //顶点2坐标
    //     0, 100, 0, //顶点3坐标
    //     0, 0, 0, //顶点4坐标
    //     0, 0, 100, //顶点5坐标
    //     50, 0, 0, //顶点6坐标
    //     0,100,0,
    //     0,0,100,
    //     0,0,0
    // ]);
    // // 创建属性缓冲区对象
    // var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组，表示一个顶点的xyz坐标
    // // 设置几何体attributes属性的位置属性
    // geometry.attributes.position = attribue;
    // // 三角面(网格)渲染模式
    // var material = new THREE.MeshLambertMaterial({
    //     color: 0xffffff,
    //     opacity:0.5,
    //     transparent:true,
    //     side: THREE.DoubleSide //两面可见
    // }); //材质对象
    // scene.add( new THREE.Mesh( geometry, material ) );

    // 纹理贴图映射到一个矩形平面上
    // var geometry = new THREE.PlaneGeometry(204, 102); //矩形平面
    // TextureLoader创建一个纹理加载器对象，可以加载图片作为几何体纹理
    // var textureLoader = new THREE.TextureLoader();
    // // 执行load方法，加载纹理贴图成功后，返回一个纹理对象Texture
    // textureLoader.load('./Earth.jpg', function(texture) {
    //     var material = new THREE.MeshLambertMaterial({
    //         // color: 0x0000ff,
    //         side: THREE.DoubleSide, //两面可见
    //         // 设置颜色纹理贴图：Texture对象作为材质map属性的属性值
    //         map: texture//设置颜色贴图属性值
    //     }); //材质对象Material
    //     var mesh = new THREE.Mesh(geometry1, material); //网格模型对象Mesh
    //     scene.add(mesh); //网格模型添加到场景中
    //
    //     //纹理贴图加载成功后，调用渲染函数执行渲染操作
    //     // render();
    // })

    // // 图片加载器
    // var ImageLoader = new THREE.ImageLoader();
    // var texture = THREE.ImageUtils.loadTexture('Earth.jpg')
    // var texture2 = THREE.ImageUtils.loadTexture('image2.png')
    // var mesh = new THREE.MeshPhongMaterial({
    //     specular: 0xffffff,
    //     color: 0x7777ff
    // });
    // var caizhi = [
    //     new THREE.MeshPhongMaterial({map:texture}),
    //     new THREE.MeshPhongMaterial({map:texture2}),
    //     mesh
    // ];
    // var cobj = new THREE.Mesh(geometry, new THREE.MeshFaceMaterial(caizhi));
    // scene.add(cobj);

    // load方法回调函数，按照路径加载图片，返回一个html的元素img对象
    // ImageLoader.load('Earth.jpg', function(img) {
    //     // image对象作为参数，创建一个纹理对象Texture
    //     var texture = new THREE.Texture(img);
    //     // 下次使用纹理时触发更新
    //     texture.needsUpdate = true;
    //     var material = new THREE.MeshLambertMaterial({
    //         map: texture, //设置纹理贴图
    //     });
    //     var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
    //     scene.add(mesh); //网格模型添加到场景中
    // });

    //sprite材质
    // var material = new THREE.SpriteMaterial( {
    //     //以canvas作为纹理
    //     map: new THREE.CanvasTexture( generateSprite() ),
    //     //混合度 加法混合
    //     blending: THREE.AdditiveBlending
    // } );
    //
    // //循环1000  添加粒子
    // for ( var i = 0; i < 1; i++ ) {
    //     particle = new THREE.Sprite( material );
    //     initParticle( particle, i * 10 );
    //     krq.add(particle);
    // }
    // scene.add(krq);


    var loader = new THREE.FontLoader();

    loader.load( 'font/gentilis_bold.typeface.json', function ( font ) {

        var geometry = new THREE.TextGeometry('Hello three1.js!', {
            font: font,
            size: 80,
            height: 5,
            curveSegments: 12,
            bevelEnabled: true,
            bevelThickness: 10,
            bevelSize: 8,
            bevelSegments: 5
        });
        var material = new THREE.MeshPhongMaterial({
            color: 0x00ff00,
            specular:0x4488ee,
            shininess:20
        })//材质对象
        var curveObject = new THREE.Mesh( geometry, material );
        scene.add(curveObject);
    })


    /**
     * 光源设置
     */
        // 点光源
    var point = new THREE.PointLight(0xAAAAAA)
    // 点光源位置
    point.position.set(400, 200, 300)
    // 将点光源添加到场景中
    scene.add(point)
    // 环境光
    var ambient = new THREE.AmbientLight(0x404040 )
    scene.add(ambient)
    /**
     * 相机设置
     */
        //窗口宽度
    var width = window.innerWidth
    //窗口高度
    var height = window.innerHeight
    //窗口宽高比
    var k = width / height
    //三维场景显示范围控制系数，系数越大，显示的范围越大
    var s = 200
    //创建相机对象
    var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000)
    //设置相机位置
    camera.position.set(200, 200, 500)
    //设置相机方向(指向的场景对象)
    camera.lookAt(scene.position)
    /**
     * 创建渲染器对象
     */
    var renderer = new THREE.WebGLRenderer()
    //设置渲染区域尺寸
    renderer.setSize(width, height)
    //设置背景颜色
    renderer.setClearColor(0xb9d3ff, 1)
    //body元素中插入canvas对象
    document.body.appendChild(renderer.domElement)
    //执行渲染操作   指定场景、相机作为参数
    renderer.render(scene, camera)
    //设置像素比
    renderer.setPixelRatio( window.devicePixelRatio );
    //间隔20ms周期性调用函数fun,20ms也就是刷新频率是50FPS(1s/20ms)，每秒渲染50次
    // setInterval("render()",20);
    // 上次的时间
    let T0 = new Date();
    // 自动旋转
    // function render() {
    //     //本次时间
    //     let T1 = new Date();
    //     //时间差
    //     let t = T1-T0;
    //     //把本次时间赋值给上次时间
    //     T0 = T1
    //     //默认保持60FPS的频率，大约每16.7ms调用一次
    //     requestAnimationFrame(render)
    //     //执行渲染操作
    //     renderer.render(scene,camera)
    //     //旋转角速度0.001弧度每毫秒
    //     mesh.rotateZ(0.001*t);
    //     // camera.rotateY(0.01)
    //     // camera.rotateZ(0.01)
    //     // camera.rotateX(0.01)
    //     // mesh.rotateX(0.01)
    //     // mesh.rotateY(0.99)
    //     // mesh.rotateZ(0.001)
    // }
    // render()
    //渲染执行
    function render1(){
        renderer.render(scene,camera)
        //默认保持60FPS的频率，大约每16.7ms调用一次
        mesh1.rotateY(0.01)
        requestAnimationFrame(render1)
    }
    render1()
    //渲染执行
    function render2(){
        renderer.render(scene,camera)
        //默认保持60FPS的频率，大约每16.7ms调用一次
        mesh2.rotateY(0.01)
        // krq.rotateY(0.1)
        // 每次渲染遍历雨滴群组，刷新频率30~60FPS，两帧时间间隔16.67ms~33.33ms
        // 每次渲染都会更新雨滴的位置，进而产生动画效果
        krq.children.forEach(sprite => {
            // 雨滴的y坐标每次减1
            sprite.position.y -= 1;
            if (sprite.position.y < 0) {
                // 如果雨滴落到地面，重置y，从新下落
                sprite.position.y = 200;
            }
        });
        // mesh3.rotateY(0.01)
        requestAnimationFrame(render2)
    }
    render2()
    var controls = new THREE.OrbitControls(camera);
    // controls.addEventListener('change', render)
    container.appendChild( renderer.domElement );

    stats = new Stats();
    container.appendChild( stats.dom );
    /**
     * 返回canvas 作为纹理
     * @returns {HTMLCanvasElement}
     */
    function generateSprite() {

        //创建canvas并设置大小
        var canvas = document.createElement( 'canvas' );
        canvas.width = 16;
        canvas.height = 16;

        //得到2d，canvas
        var context = canvas.getContext( '2d' );
        //渐变方式
        var gradient = context.createRadialGradient( canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2 );

        /*gradient.addColorStop( 0, 'rgba(255,255,255,1)' );
        gradient.addColorStop( 0.2, 'rgba(0,255,255,1)' );
        gradient.addColorStop( 0.4, 'rgba(0,0,64,1)' );
        gradient.addColorStop( 1, 'rgba(0,0,0,1)' );*/

        gradient.addColorStop( 0, 'rgba(255,255,255,1)' );
        gradient.addColorStop( 0.6, 'rgba(0,255,255,.5)' );
        gradient.addColorStop( 0.8, 'rgba(0,53,169,1)' );
        gradient.addColorStop( 1, 'rgba(0,0,0,1)' );
        //填充方式
        context.fillStyle = gradient;
        //填充矩形
        context.fillRect( 0, 0, canvas.width, canvas.height );

        return canvas;

    }


    /**
     * 粒子 延迟发散
     * @param particle
     * @param delay
     */
    function initParticle( particle, delay ) {
        //粒子
        var particle = this instanceof THREE.Sprite ? this : particle;
        var delay = delay !== undefined ? delay : 0;
        //粒子大小以及位置
        particle.position.set( 0, 0, 0 );
        particle.scale.x = particle.scale.y = Math.random() * 32 + 16;
        //下面是一系列的动画
        var xx = Math.random()* 400 -200;
        var yy = -Math.cos((Math.PI/400) * xx)*500;
        //位移
        new TWEEN.Tween( particle.position )
            .delay( delay )
            // .to( { x: Math.random() * 4000 - 2000, y: Math.random() * 1000 - 500, z: Math.random() * 4000 - 2000 }, 10000 )
            .to({x:xx,y:yy,z:Math.random()*-100 + 50},3000)
            .start();
        //理解为存活时间    x加一个判断
        if(Math.abs(xx) > 150){
            new TWEEN.Tween(particle)
                .delay(delay)
                .to({}, 0)
                .onComplete(initParticle)
                .start();
        }else {
            new TWEEN.Tween(particle)
                .delay(delay)
                .to({}, 2000)
                .onComplete(initParticle)
                .start();
        }
        //大小
        new TWEEN.Tween( particle.scale )
            .delay( delay )
            .to( { x: 0.01, y: 0.01 }, 2000 )
            .start();
    }
</script>
</body>
</html>
